# -*- coding: utf-8 -*-

# @Time : 2020/2/10 9:03
# @Author : WYT
# @Site :
# @File : hzflowOperation.py
# @Software: PyCharm
import os
import socket
import sys
from copy import deepcopy

# from base.BaseMethod import BM
from sqlalchemy import or_

from util.g import g
from settings import CLASSMODELMAPPING, CLASSDATADICT as dic, web_type, FIELDCLASSMAPPING, site_type, \
    MultiRecordList, base_path

from hzflowModel.hzflow import ent_flow_data as data, ent_error_info as error, ent_records_status as records, session
from hzflowModel.hzflow import ent_flow_datalog as datalog
from hzflowModel.hzflow import ent_datasync_reason as reason
from hzflowModel.hzflow import ent_note_record as note
from hzflowModel.hzflow import domain
from util.inform.sendEmail import sendEmail
from util.sys_dict import domain_one


class hzflowOperation():
    error = -1
    completed = 1
    errorLess = 2

    POOL = g.hzflow_pool
    dict_cursor = g.dict_cursor

    @staticmethod
    def get_host():
        from configparser import ConfigParser

        cfg = ConfigParser()
        cfg.read("{}\\config.ini".format(base_path))
        host_str = cfg.get("runtime", "host")
        # return str(socket.gethostbyname(socket.gethostname()))
        return host_str

    # 存储国网技术领域
    @staticmethod
    def add_domain(id, parent_id, name):
        do = session.query(domain).filter_by(id=id, parent_id=parent_id, name=name).first()
        print("do: -{}-".format(do))
        if not do:
            record = domain(id=id, parent_id=parent_id, name=name)
            session.add(record)
            session.commit()

    """
    根据 parent_id 获取 技术领域 并 转为 name : id 形式的 dict
    """
    @staticmethod
    def get_domain_by_parent_id(parent_id):
        d_list = session.query(domain).filter_by(parent_id=parent_id).all()
        return {i.name.strip():i.id for i in d_list}

    @staticmethod
    def get_domain_by_namelist(hitech_field_namelist):
        namelist = hitech_field_namelist.split(",")
        num = len(namelist)
        if num < 1:
            return {}
        one_id = domain_one.get(namelist[0])
        one_next_dict = hzflowOperation.get_domain_by_parent_id(parent_id=one_id)
        if num < 2:
            two_id = one_next_dict.get("无")
        else:
            two_id = one_next_dict.get(namelist[1])
        two_next_dict = hzflowOperation.get_domain_by_parent_id(parent_id=two_id)
        if num < 3:
            thr_id = two_next_dict.get("无")
        else:
            thr_id = two_next_dict.get(namelist[2])
        a = {}
        a["domain1"] = str(one_id)
        a["domain2"] = str(two_id)
        a["domain3"] = str(thr_id)
        return a

    @staticmethod
    def tran_to_data(co_id=None, year=None, site=site_type, status=0):
        if not co_id or not year:
            return
        try:
            # session.begin(subtransactions=True)
            li = session.query(data).filter_by(
                co_id=co_id, year=year, res_code=site, web_type=web_type).with_for_update().all()
            li_id = []
            for i in li:
                log = datalog()
                for attr in dir(i):
                    if attr.startswith("__") or attr.startswith("_") or attr == "id":
                        continue
                    setattr(log, attr, getattr(i, attr))
                log.status = status
                li_id.append(i.id)
                session.add(log)
            # session.query(datalog).filter(datalog.id.in_(li_id)).delete()
            if li_id:
                session.execute(
                    """delete from ent_flow_data where id in ({})""".format(
                    ",".join([str(a) for a in li_id])))
            session.commit()

        except Exception as err:
            err_msg = "{} file:{} lines:{}".format(
                err, err.__traceback__.tb_frame.f_globals["__file__"],
                err.__traceback__.tb_lineno)
            session.rollback()
            raise Exception(err_msg)
            # raise Exception(err_msg)



    @staticmethod
    def add_log(co_id="", year=None):
        obj = session.query(data).filter_by(year=year, res_code=site_type, web_type=web_type,
                                           co_id=co_id).with_for_update().first()
        # print("obj: {}".format(obj))
        if not obj:
            try:
                record = data(year=g.year, web_type=web_type, res_code=site_type, co_id=co_id,
                             # host_process="{}:{}".format(hzflowOperation.get_host(), os.getpid()),
                             mark_info=hzflowOperation.get_host())
                session.add(record)
                session.commit()
            except Exception as err:
                g.logger.error("create error: {}".format(err))
                record = hzflowOperation.get_log(co_id=co_id, year=year)
            g.is_first_entry = True
            return record, False
        else:
            session.close()
            return obj, True

    @staticmethod
    def add_log_after_delete_record(co_id="", year=None):
        obj = session.query(data).filter_by(year=year, res_code=site_type, web_type=web_type,
                                           co_id=co_id).with_for_update().first()
        if not obj:
            record = data(year=g.year, web_type=web_type, res_code=site_type, co_id=co_id,
                         # host_process="{}:{}".format(hzflowOperation.get_host(), os.getpid()),
                         mark_info=hzflowOperation.get_host(), first_entry_delete=1)
            session.add(record)
            session.commit()
            g.is_first_entry = True
            return record
        else:
            obj.first_entry_delete = 1
            session.add(obj)
            session.commit()
            return obj

    @staticmethod
    def add_reason(co_id=0, year=0, fb_time=0, rt_id=0, rt_name="", biz_code="", biz_name="", rsn_desc="", add_desc=""):

        record = reason(co_id=co_id, year=year, fb_time=fb_time, web_type=web_type, rt_id=rt_id, rt_name=rt_name,
                        res_code=site_type, biz_code=biz_code, biz_name=biz_name, rsn_desc=rsn_desc, add_desc=add_desc)
        session.add(record)
        try:
            session.commit()
        except Exception as err:
            g.logger.error("{} create ent_datasync_reason err:{}".format(sys._getframe().f_code.co_name, err))
            session.rollback()
        else:
            session.close()

    @staticmethod
    def get_log(co_id=None, year=None):
        obj = None
        try:
            obj = session.query(data).filter_by(year=year, web_type=web_type, res_code=site_type,
                                               co_id=co_id).with_for_update().first()
        except Exception as err:
            session.rollback()
        else:
            session.close()
        return obj

    @classmethod
    def get_logs(cls, co_id=None, year=None):
        objs = None
        try:
            objs = session.query(data).filter_by(year=year, res_code=site_type, co_id=co_id).all()
        except Exception:
            session.rollback()
        else:
            session.close()
        return objs

    @classmethod
    def emptyProcess(cls, record=None, co_id=None, year=None):
        obj = None
        if record:
            obj = record
        else:
            obj = session.query(data).filter_by(year=year, web_type=web_type, res_code=site_type,
                                               co_id=co_id).with_for_update().first()
            if not obj:
                record = data(year=g.year, web_type=web_type, co_id=co_id)
                session.add(record)
                session.commit()
        for i in FIELDCLASSMAPPING:
            if not i:
                continue
            if getattr(obj, i) != 0:
                setattr(obj, i, 0)
        session.add(obj)
        session.commit()
        g.record = obj

    @classmethod
    def emptyLoginSmsStatus(cls, co_id=None, year=None, condition={}):
        update_sql = """update ent_flow_data set sms_status=0, login_status=0, is_compress=0 where \
        co_id={} and year={} and res_code='{}'""".format(co_id, year, site_type)
        if condition:
            update_sql += " and " + " and ".join([f"{k}='{v}'" for k, v in condition.items()])
        try:
            session.execute(update_sql)
            session.commit()
        except Exception as err:
            g.logger.error("{} error: {} file: {} line: {}".format(sys._getframe().f_code.co_name, err,
                                                                   err.__traceback__.tb_frame.f_globals.get("__file__"),
                                                                   err.__traceback__.tb_lineno))
            session.rollback()

    # TODO 检查材料上传状态
    @staticmethod
    def checkProcess(co_id=None, year=None):
        obj = None
        try:
            obj = session.query(data).filter_by(co_id=co_id, year=year, res_code=site_type,
                                               web_type=web_type).with_for_update().first()
        except Exception as err:
            session.rollback()
        else:
            session.close()
        if not obj:
            return False
        else:
            flag = True
            for i in FIELDCLASSMAPPING:
                if not i:
                    continue
                if getattr(obj, i) != 1:
                    if i == "upload_status":
                        if g.need_file:
                            flag = False
                    else:
                        flag = False
            return flag

    @staticmethod
    def checkProcessByRecord(record):
        flag = True
        for i in FIELDCLASSMAPPING:
            if getattr(record, i) != 1:
                if i == "upload_status":
                    if g.need_file:
                        flag = False
                else:
                    flag = False
        return flag

    @staticmethod
    def update_host_process(obj=None, mark_info=""):
        # "{}:{}".format(socket.gethostbyname(socket.gethostname()), os.getpid())
        #
        if mark_info == "":
            return
        if obj:
            obj.mark_info = mark_info
            session.add(obj)
            session.commit()

    @staticmethod
    def update_host_process_by_co_id(co_id=0, year=0, host_process=""):
        obj = None
        try:
            obj = session.query(data).filter_by(co_id=co_id, year=year, web_type=web_type, res_code=site_type)
        except Exception as err:
            session.rollback()
        else:
            session.close()
        hzflowOperation.update_host_process(obj=obj, mark_info=host_process)

    @staticmethod
    def update_field(obj=None, field_name="", field_value=""):
        if type(obj) == list:
            for o in obj:
                setattr(o, field_name, field_value)
                session.add(o)
                session.commit()
        else:
            setattr(obj, field_name, field_value)
            session.add(obj)
            session.commit()

    @staticmethod
    def update_fields(obj=None, map={}):
        if obj is None:
            obj = hzflowOperation.get_log(co_id=g.co_id, year=g.year)
        if not map:
            return
        if type(obj) == list:
            for o in obj:
                for k, v in map.items():
                    setattr(o, k, v)
                session.add(o)
                session.commit()
        else:
            for k, v in map.items():
                setattr(obj, k, v)
            session.add(obj)
            session.commit()

    @staticmethod
    def update_field_by_co_id(co_id=None, year=None, field_name="", field_value=""):
        obj = hzflowOperation.get_log(co_id=co_id, year=year)
        hzflowOperation.update_field(obj=obj, field_name=field_name, field_value=field_value)
        pass

    @staticmethod
    def changeLog(class_name='', value=None):
        g.logger.info("{}: {}".format(class_name, value))
        field = CLASSMODELMAPPING.get(class_name).get('field')
        # 不更新 上传状态的情况
        if not field:
            return
        obj = session.query(data).filter_by(co_id=g.co_id, year=g.year, web_type=web_type, res_code=site_type).first()
        record = deepcopy(obj)
        setattr(obj, field, value)
        session.commit()
        return record

    def commonExceptionModel(self, class_name='', err=''):

        g.logger.error(f'error in {class_name} error message: {err}')

        log = self.changeLog(class_name=class_name, value=self.error)
        err_record = error(log_id=log.id, error_class=class_name, error_message=str(err),
                           error_field=CLASSMODELMAPPING.get(class_name).get('field'))
        session.add(err_record)
        try:
            session.commit()
        except Exception as err:
            g.logger.error("save err error err: {}".format(err))
        else:
            session.close()

        # # # TODO 这里可以使用 logger 记录日志 并记录 class_name

    def commonModel(self, class_name='', value=errorLess):
        self.changeLog(class_name=class_name, value=value)

    @classmethod
    def add_note_record(cls, co_id, year, fb_time, res_code, sign, phones, template, params):
        if type(params) == dict:
            params = params.get("resinfo")
        try:
            try:
                obj = session.query(note).filter_by(co_id=co_id, year=year, fb_time=fb_time, res_code=res_code, sign=sign,
                                    phones=phones, template=template, resinfo=params).first()
                if not obj:
                    note_obj = note(co_id=co_id, year=year, fb_time=fb_time, res_code=res_code, sign=sign,
                                    phones=phones, template=template, resinfo=params)
                    session.add(note_obj)
                    session.commit()
            except Exception as err:
                msg = "create error co_id={} year={} fb_time={} res_code={} sign={} phones={} template={} params={} err: {}\n file: {} line: {}".format(
                    co_id, year, fb_time, res_code, sign, phones, template, params, err,
                    err.__traceback__.tb_frame.f_globals.get("__file__"), err.__traceback__.tb_lineno)
                g.logger.error(msg)
                # sendEmail(subject="autoflow", content=msg).send_mail()
                session.rollback()
                return False
            else:
                return True
        except Exception as err:
            msg = "{} error: {} file: {} line: {}".format(sys._getframe().f_code.co_name, err,
                                                          err.__traceback__.tb_frame.f_globals.get("__file__"),
                                                          err.__traceback__.tb_lineno)
            g.logger.error(msg)
            raise Exception(msg)

    @classmethod
    def select_note_record_by_info(cls, co_id=None, year=None, fb_time=None, res_code=None, sign=None, phones=None,
                                   template=None, params=None, changed_status=None, check_status=0):
        if type(params) == dict:
            params = params.get("resinfo")
        obj = None
        select_sql = """select * from ent_flow_data where co_id={} and year={} and res_code='{}'""".format(co_id,
                                                                                                              year,
                                                                                                              site_type)
        update_sql = """update ent_flow_data set sms_status={} where co_id={} and year={} and res_code='{}' and sms_status={}""".format(
            changed_status, co_id, year, res_code, check_status)
        client = cls.POOL.connection()
        cursor = client.cursor(cursor=cls.dict_cursor)
        try:
            cursor.execute(select_sql)
            obj = cursor.fetchall()

            sms_list = [i.get("sma_status") for i in obj]
            if any(sms_list):
                try:
                    cursor.execute(update_sql)
                    count = cursor.rowcount
                except Exception as err:
                    client.rollback()
                else:
                    client.commit()
                cls.add_note_record(co_id=co_id, year=year, fb_time=fb_time, res_code=res_code, sign=sign,
                                    phones=phones, template=template, params=params)
                return False
            else:
                count = None
                try:
                    cursor.execute(update_sql)
                    count = cursor.rowcount
                except Exception as err:
                    client.rollback()
                else:
                    client.commit()
                if count >= len(sms_list):
                    cls.add_note_record(co_id=co_id, year=year, fb_time=fb_time, res_code=res_code, sign=sign,
                                        phones=phones, template=template, params=params)
                    return True
                else:
                    return False

        except Exception as err:
            g.logger.error(
                "{} error: {} sql: {} file: {} lines: {}".format(sys._getframe().f_code.co_name, err, select_sql,
                                                                 err.__traceback__.tb_frame.f_globals.get("__file__"),
                                                                 err.__traceback__.tb_lineno))

            return False
        finally:
            cursor.close()
            client.close()

    def recordsModel(self, error_ids=[], completed_ids=[], class_name=''):
        a = dic.get(class_name)
        source = f"{a.get('database')}.{a.get('table')}"
        compl = len(completed_ids)
        error = len(error_ids)
        total = compl + error
        c_ids = ','.join(completed_ids)
        e_ids = ','.join(error_ids)

        if not error_ids and class_name in MultiRecordList:
            self.changeLog(class_name=class_name, value=self.completed)
        else:
            obj = self.changeLog(class_name=class_name, value=self.error)
            r = records(log_id=obj.id, source_table=source, record_num=total, completed_num=compl, completed_ids=c_ids,
                        error_num=error, error_ids=e_ids, error_class=class_name,
                        error_field=CLASSMODELMAPPING.get(class_name).get('field'))
            session.add(r)
            session.commit()

    @classmethod
    def get_recode_by_co_ids(cls, co_ids, year):
        objs = None
        try:
            objs = session.query(data).filter(data.res_code == site_type, data.res_code == site_type,
                                              data.web_type == web_type,
                                              data.year == year,
                                             or_(data.mark_info == cls.get_host(), data.mark_info == None,
                                                 data.mark_info == ""),
                                              data.co_id.in_(co_ids)).with_for_update().all()
        except Exception as err:
            session.rollback()
        else:
            session.close()
        return objs

    @classmethod
    def check_host(cls, co_id=0, year=0):
        obj = None
        try:
            obj = session.query(data).filter(
                data.res_code == site_type, data.res_code == site_type, data.web_type == web_type, data.year == year,
                or_(data.mark_info == cls.get_host(), data.mark_info == None, data.mark_info == ""),
                                             data.co_id == co_id
                                            ).with_for_update().all()
        except Exception as err:
            session.rollback()
        else:
            session.close()
        if not obj:
            return False
        elif obj.mark_info == cls.get_host() or not obj.mark_info:
            return False
        else:
            return True


if __name__ == '__main__':
    hzflowOperation.tran_to_data(co_id=121629, year=2021)
    # log = session.query(log).filter_by(co_id=g.co_id).first()
    #
    # function
    # res = hzflowOperation.get_domain_by_namelist(hitech_field_namelist="电子信息,软件,基础软件")
    # print(res)
    def a():
        ...


    # b = ...  # type: str
    # print(type(a))
    # print(log.id)

    # a, flag = hzflowOperation.add_log(co_id=30756, year=2020)
    # print(a.web_type, a.host_process)
    # print(hzflowOperation.checkProcess(co_id=547656, year=2020))
    # res = hzflowOperation.add_log(co_id=547656, year=2020)
    # print(res)
